<?php

namespace ASW\Utility;

class Folder
{
    public static function eachFiles(string $folderPath, callable $callback, array $ignoreFolderNames = []): bool
    {
        if (!file_exists($folderPath)) return false;
        if (!is_dir($folderPath)) return false;
        if (false === $dir = opendir($folderPath)) return false;

        $foundFail = false;
        while (false !== $item = readdir($dir)) {
            if ($item == '.' || $item == '..') continue;
            $itemFullPath = $folderPath . DIRECTORY_SEPARATOR . $item;
            if (is_file($itemFullPath)) {
                if (false === $callback($itemFullPath)) {
                    $foundFail = true;
                    break;
                }
            } else if (!in_array($item, $ignoreFolderNames)) {
                static::eachFiles($itemFullPath, $callback, $ignoreFolderNames);
            }
        }
        closedir($dir);
        return !$foundFail;
    }

    /**
     * 递归清空目录(不删除目录及子目录, 仅删除文件)
     *
     * @param string $folderPath
     *
     * @return bool
     */
    public static function clear(string $folderPath): bool
    {
        return static::eachFiles($folderPath, function ($filePath) {
            return false !== @unlink($filePath);
        });
    }

    /**
     * 递归删除目录
     *
     * @param string $folderPath
     *
     * @return bool
     */
    public static function delete(string $folderPath): bool
    {
        if (!self::clear($folderPath)) return false;
        if (false === @rmdir($folderPath)) return false;
        return true;
    }

    /**
     * 递归拷贝目录
     *
     * @param string $sourceFolderPath 源目录
     * @param string $targetFolderPath 目标目录
     *
     * @return bool
     */
    public static function copy(string $sourceFolderPath, string $targetFolderPath): bool
    {
        return static::eachFiles($sourceFolderPath, function ($sourceFilePath) use ($sourceFolderPath, $targetFolderPath) {
            $relativeFileName = str_replace($sourceFolderPath, '', $sourceFilePath);
            $targetFilePath   = $targetFolderPath . DIRECTORY_SEPARATOR . $relativeFileName;

            return false !== @copy($sourceFilePath, $targetFilePath);
        });
    }

    /**
     * 递归创建目录
     *
     * @param string $folderPath
     * @param int $permission
     *
     * @return bool
     */
    public static function create(string $folderPath, int $permission = 0666): bool
    {
        if (is_dir($folderPath)) return true;
        if (false === self::create(dirname($folderPath))) return false;
        if (false === @mkdir($folderPath, $permission)) return false;
        return true;
    }

    /**
     * 统计目录尺寸, 统计失败返回 -1
     *
     * @param string $folderPath
     *
     * @return int
     */
    public static function getSize(string $folderPath): int
    {
        $folderSize = 0;
        $allSuccess = static::eachFiles($folderPath, function ($sourceFilePath) use (&$folderSize) {
            if (false === $fileSize = filesize($sourceFilePath)) return false;
            $folderSize += $fileSize;
            return true;
        });
        return $allSuccess ? $folderSize : -1;
    }
}